package org.hairball.graph;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Filters a create only showing those nodes with a given number of dependencies
 */
public class MinDependencyFilterGraph implements HairballGraph {
    private HairballGraph underlyingGraph;
    private int minLinks;

    public MinDependencyFilterGraph(HairballGraph underlyingGraph, int minLinks) {
        this.underlyingGraph = underlyingGraph;
        this.minLinks = minLinks;
    }

    public void visitEdges(EdgeVisitor edgeVisitor) {

    }

    public void visitNodes(final NodeVisitor nodeVisitor) {
        final Map<String, Integer> outboundCount = buildOutgoingLinkCount();

        final Set<String> dependantsToInclude = new HashSet<String>();
        for (String nodeName : outboundCount.keySet()) {
            int count = outboundCount.get(nodeName);

            if (count >= minLinks) {
                dependantsToInclude.add(nodeName);
            }
        }

        final Set<String> nodesToVisit = new HashSet<String>();
        underlyingGraph.visitEdges(new EdgeVisitor() {

            public void visit(String fromNode, String toNode, String edgeType) {
                if (dependantsToInclude.contains(fromNode)) {
                    nodesToVisit.add(fromNode);
                    nodesToVisit.add(toNode);
                }
            }
        });

        for (String nodeName : nodesToVisit) {
            nodeVisitor.visit(nodeName, true);
        }
    }

    private Map<String, Integer> buildOutgoingLinkCount() {
        final Map<String, Integer> outboundCount = new HashMap<String, Integer>();

        underlyingGraph.visitEdges(new EdgeVisitor() {

            public void visit(String fromNode, String toNode, String edgeType) {
                if (!outboundCount.containsKey(fromNode)) {
                    outboundCount.put(fromNode, 1);
                } else {
                    int count = outboundCount.get(fromNode) + 1;
                    outboundCount.put(fromNode, count);
                }
            }
        });
        return outboundCount;
    }
}
